package controller;

import simulator.enums.Direction;
import simulator.enums.LaneType;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import net.minidev.json.parser.JSONParser;
import net.minidev.json.parser.ParseException;

public class Protocol
{
	/** true: count cars when they pass far loop. false: count on close loop */
	public static final boolean DO_FAR_LOOP_COUNTING = true;
	
	private final String	STARTTIME_KEY	= "starttime";
	private final String	MULTIPLIER_KEY	= "multiplier";
	private final String	LIGHT_KEY		= "light";
	private final String	TYPE_KEY		= "type";
	private final String	LOOP_KEY		= "loop";
	private final String	EMPTY_KEY		= "empty";
	private final String	TO_KEY			= "to";

	private JSONParser		_parser;
	private Controller		_controller;
	private CrossRoad		_crossRoad;

	public Protocol(Controller controller, CrossRoad crossRoad)
	{
		_parser = new JSONParser(JSONParser.DEFAULT_PERMISSIVE_MODE);
		_crossRoad = crossRoad;
		_controller = controller;
	}

	public void HandleMessage(String msg)
	{
		//JSONObject test = new JSONObject();
		//test.put("starttime", "23:00");
		//test.put("multiplier", 1);
		//msg = test.toString();	
		Object data;

		try
		{
			data = _parser.parse(msg);

			if (data instanceof JSONObject)
			{
				HandleJSONObject((JSONObject) data);
			}
			if (data instanceof JSONArray)
			{
				JSONArray array = (JSONArray) data;
				for (int i = 0; i < array.size(); i++)
				{
					Object o = array.get(i);
					HandleJSONObject((JSONObject) o);
				}
			}
		}
		catch (ParseException e)
		{
			e.printStackTrace();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	@SuppressWarnings("unused")
	private void HandleJSONObject(JSONObject jo)
	{
		if (jo.containsKey(STARTTIME_KEY))
		{
			String time = (String) jo.get(STARTTIME_KEY);
			ControllerTime.getInstance().setTime(time);
			_controller.start();
		}
		else if (jo.containsKey(MULTIPLIER_KEY))
		{
			Object mul = jo.get(MULTIPLIER_KEY);

			if (mul instanceof Integer)
			{
				int multiplier = (int) jo.get(MULTIPLIER_KEY);
				ControllerTime.getInstance().setMultiplier(multiplier);
			}
			else
			{
				System.out.println("Dropped incorrect multiplier package (value not integer)");
			}
		}
		else
		{
			String loop = (String) jo.get(LOOP_KEY);
			loop = loop.trim();
			Object em = jo.get(EMPTY_KEY);
			boolean empty = false;
			if(em instanceof Boolean)
			{
				empty = (Boolean) em;
			}
			else if(em instanceof String)
			{
				empty = Boolean.valueOf((String) em);
			}
			
			//Boolean empty = (Boolean) jo.get(EMPTY_KEY);

			String typ = (String) jo.get(TYPE_KEY);
			boolean flc = DO_FAR_LOOP_COUNTING && (typ.equalsIgnoreCase("car"));
			
			if (loop == null)
			{
				loop = "close";
				empty = false;
			}
			else if (loop.equals("far"))
			{
				if(!empty && flc)
				{
					loopEntered(jo);
				}
			}
			else if (loop.equals("close"))
			{
				//System.out.println("close loop (empty=" + empty + ")");
				if (empty)
				{
					loopLeft(jo);
				}
				if (!empty && !flc)
				{
					loopEntered(jo);
				}
			}
			else
			{
				System.out.println("Invalid JSON key value: " + LOOP_KEY + " " + loop);
			}
		}
	}

	private void loopEntered(JSONObject loopObject)
	{
		String light = (String) loopObject.get(LIGHT_KEY);

		Direction dir = Direction.getFromChar(light.charAt(0));
		Character cid = light.charAt(1);
		int id = Integer.parseInt(cid.toString());
		LaneType lanetype = LaneType.fromID(id);
		if (lanetype != LaneType.VEHICLE_EXIT) _crossRoad.loopEntered(dir, lanetype);
	}

	private void loopLeft(JSONObject loopObject)
	{
		String light = (String) loopObject.get(LIGHT_KEY);

		Direction dir = Direction.getFromChar(light.charAt(0));
		Character cid = light.charAt(1);
		int id = Integer.parseInt(cid.toString());
		LaneType lanetype = LaneType.fromID(id);

		if (lanetype != LaneType.VEHICLE_EXIT) _crossRoad.loopLeft(dir, lanetype);
	}
}
